package org.clockwise.feature;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import org.clockwise.multimethod.PageRank;
import org.clockwise.nlpir.ResultParser;
import org.clockwise.nlpir.TestNLPIR;
import org.clockwise.util.MyFileWriter;
import org.clockwise.util.MyStrUtil;

/**
 * This class parses labeled text and store the information, 
 * including the keyword, position, context and so on.
 * It is one of the two sources of feature extractor.
 * The other one is User.
 * @author WangYan
 *
 */
public class QueryContext {
	
	String labeledText = null;					// the copy of origin labeled string
	String unlabeledText = null;				// the copy of unlabeled string
	
//	HashMap<String, Integer> dict;				// String: keyword, Integer: start position in unlabeled line
	String[] words = null;						// the words separated by NLPIR
	String[] labels = null;						// the labels of words given by NLPIR
	int[] position = null;						// the start position of each word, used to find word rank given position
	
	public List<TextLabel> labelList = null;
	public List<Query> queryList = null;
	
	public QueryContext(List<String> list, AccountPool accountPool) {
		Iterator<String> iter = list.iterator();
		labelList = new ArrayList<TextLabel>();
		queryList = new ArrayList<Query>();
		
		while (iter.hasNext()) {
			String line = iter.next();
			if (line.contains("LabeledText")) {
				labeledText = MyStrUtil.getRidOfLabels(line);
			}
			else if (line.contains("UnlabeledText")) {
				unlabeledText = MyStrUtil.getRidOfLabels(line);
			}
			else if (line.contains("words")) {
				words = MyStrUtil.getRidOfLabels(line).split("\t");
			}
			else if (line.contains("labels")) {
				labels = MyStrUtil.getRidOfLabels(line).split("\t");
			}
			else if (line.contains("position")) {
				position = MyStrUtil.splitStrToInt(MyStrUtil.getRidOfLabels(line), "\t");
				if (position == null) {
					System.out.println(line);
				}
			}
			else if (line.contains("TextLabel")) {
				labelList.add(new TextLabel(MyStrUtil.getRidOfLabels(line)));
			}
		}
		
		queryList = new ArrayList<Query>();
		Iterator<TextLabel> tlIter = labelList.iterator();
		while (tlIter.hasNext()) {
			TextLabel tl = tlIter.next();
			queryList.add(new Query(tl, this, accountPool));
		}
	}
	
	public void recordInfo(MyFileWriter mfw) {
		mfw.write("<QueryContext>\n");
		mfw.write("<LabeledText>" + labeledText + "</LabeledText>\n");
		mfw.write("<UnlabeledText>" + unlabeledText + "</UnlabeledText>\n");
		mfw.write("<words>" + MyStrUtil.mergeStrArray(words, "\t") + "</words>\n");
		mfw.write("<labels>" + MyStrUtil.mergeStrArray(labels, "\t") + "</labels>\n");
		mfw.write("<position>" + MyStrUtil.mergeStrArray(position, "\t") + "</position>\n");
		Iterator<TextLabel> iter = labelList.iterator();
		while (iter.hasNext()) {
			mfw.write("<TextLabel>" + iter.next().getRecordString() + "</TextLabel>\n");
		}
		mfw.write("</QueryContext>\n");
	}
	
	public QueryContext(String labeledLine, AccountPool accountPool) {
		
		this.labeledText = labeledLine;
		labelList = new ArrayList<TextLabel>();
		
		int begin = 0, end = 0;
		labeledText = MyStrUtil.getRidOf(labeledLine, "#");
		unlabeledText = "";
		String copy = labeledText;
		while (copy.contains("<")) {
			begin = copy.indexOf("<");
			end = copy.indexOf(">");
			if (begin >= end || begin < 0) {
				System.out.println("Wrong format : \'<\' and \'>\' are not in pairs. Original copy: ");
				System.out.println(copy);
				break;
			}
			unlabeledText += copy.substring(0, begin);
			String label = copy.substring(begin + 1, end);
			copy = copy.substring(end + 1, copy.length());
			begin = copy.indexOf("<");
			
			if (begin < 0) {
				System.out.println("Wrong label: begin mark and end mark are not paired");
				System.out.println("\t" + copy);
				break;
			}
			String text = copy.substring(0, begin);
			if (text.length() == 0) {
				System.out.println("Error: " + copy);
			}
			else {
				TextLabel tl = new TextLabel(label, text, unlabeledText.length());
				labelList.add(tl);
			}
			
			unlabeledText += text;
			
			end = copy.indexOf(">");
			if (begin >= end) {
				System.out.println("Wrong label: begin mark and end mark are not paired");
				break;
			}
			
			copy = copy.substring(end + 1, copy.length());
			
			unlabeledText = MyStrUtil.getRidOf(unlabeledText, "null");
			
			List<List<String>> dual = ResultParser.parseWords(TestNLPIR.test(unlabeledText));
			words = new String[dual.get(0).size()];
			labels = new String[dual.get(1).size()];
			dual.get(0).toArray(words);
			dual.get(1).toArray(labels);
			for (int i = 0; i < words.length; i++) {
				words[i] = words[i].toLowerCase();
			}
			position = new int[words.length + 1];
			position[0] = 0;
			for (int i = 0; i < words.length; i++) {
				position[i + 1] = position[i] + words[i].length();
			}
		}
		unlabeledText += copy;
		unlabeledText = unlabeledText.toLowerCase();
		
		queryList = new ArrayList<Query>();
		Iterator<TextLabel> tlIter = labelList.iterator();
		while (tlIter.hasNext()) {
			TextLabel tl = tlIter.next();
			
//			for (int i = 0; i < tl.segWords.length; i++) {
//				System.out.print(tl.segWords[i] + "/");
//			}
//			System.out.println("");
			Query query = new Query(tl, this, accountPool);
			if (query.isLinked && query.findCorrect && query.potential.size() > 0)
				queryList.add(query);
		}
	}
	
	public int findWordRank(int pos) {
		int rank = 0;
		while (rank < words.length && position[rank] < pos) {
			rank++;
		}
		return rank;
	}
	
	/**
	 * Warning: After wash queries, the labelList may not be compatible with
	 * the queryList.
	 */
	public void washQuery() {
		List<Query> newql = new ArrayList<Query>();
		Iterator<Query> qIter = queryList.iterator();
		while (qIter.hasNext()) {
			Query query = qIter.next();
			if (query.isLinked && query.findCorrect && query.featureList.size() > 0) {
				newql.add(query);
			}
		}
		this.queryList.clear();
		this.queryList = newql;
	}
	
	public double[] getMaxFeature() {
		double[] max = null;
		Iterator<Query> iter = this.queryList.iterator();
		while (iter.hasNext()) {
			double[] submax = iter.next().getMaxFeature();
//			System.out.print("\t");
//			for (int i = 0; i < submax.length; i++) {
//				System.out.print(submax[i] + "\t");
//			}
//			System.out.println("");
			if (max == null) {
				max = new double[submax.length];
			}
			for (int i = 0; i < submax.length; i++) {
				if (max[i] < submax[i]) {
					max[i] = submax[i];
				}
			}
		}
		if (max == null) {
			max = new double[PageRank.weight.length];
			Arrays.fill(max, 0);
		}
		return max;
	}
	
	public void normalize(double[] max) {
		Iterator<Query> iter = this.queryList.iterator();
		while (iter.hasNext()) {
			iter.next().normalize(max);
		}
	}
	
}
